/*
 * Entitypicker
 *
 * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Depends:
 *	ui.core.js
 *
 * Modified from Datepicker by:
 *  Marek Rost (stripes-crud)
 */

(function($) { // hide the namespace

    $.extend($.ui, { entitypicker: { version: "@VERSION" } });

    var PROP_NAME = 'entitypicker';

    /* Entity picker manager.
     Use the singleton instance of this class, $.entitypicker, to interact with the picker.
     Settings for (groups of) pickers are maintained in an instance object,
     allowing multiple different settings on the same page. */

    function Entitypicker() {
        this.debug = false; // Change this to true to start debugging
        this._curInst = null; // The current instance in use
        this._keyEvent = false; // If the last event was a key event
        this._disabledInputs = []; // List of entity picker inputs that have been disabled
        this._entitypickerShowing = false; // True if the popup picker is showing , false if not
        this._inDialog = false; // True if showing within a "dialog", false if not
        this._mainDivId = 'ui-entitypicker-div'; // The ID of the main entitypicker division
        this._inlineClass = 'ui-entitypicker-inline'; // The name of the inline marker class
        this._appendClass = 'ui-entitypicker-append'; // The name of the append marker class
        this._triggerClass = 'ui-entitypicker-trigger'; // The name of the trigger marker class
        this._dialogClass = 'ui-entitypicker-dialog'; // The name of the dialog marker class
        this._disableClass = 'ui-entitypicker-disabled'; // The name of the disabled covering marker class
        this._unselectableClass = 'ui-entitypicker-unselectable'; // The name of the unselectable cell marker class
        this._currentClass = 'ui-picker-current-day'; // The name of the current day marker class
        this._dayOverClass = 'ui-entitypicker-days-cell-over'; // The name of the day hover marker class
        this.regional = []; // Available regional settings, indexed by language code
        this.regional[''] = { // Default regional settings
            submitText: 'Ok', // Display text for close link
            nullText: 'Clear', // Display text for no selection
            cancelText: 'Cancel' // Display text for cancel button
        };
        this.xmlHttpObject = null;
        this._defaults = { // Global defaults for all the entity picker instances
            showOn: 'focus', // 'focus' for popup on focus,
            // 'button' for trigger button, or 'both' for either
            entityName: 'Entity', // Name of choosen entity
            innerJspFile: 'EntityPickerList.jsp', // Name of the file to show in picker
            labelText: 'Entity Picker', // Text in the picker headline
            hiddenInputId: 'EntityKey', // Name of the hidden input with primary key
            appendText: '', // Display text following the input box, e.g. showing the format
            buttonText: '...', // Text for trigger button
            buttonImage: '', // URL for trigger button image
            buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
            duration: '_default', // Duration of display/closure
            beforeShow: null, // Function that takes an input field and
            // returns a set of custom settings for the entity picker
            onClose: null, // Define a callback function when the entitypicker is closed
            autoSize: false // True to size the input for the entity format, false to leave as is
        };
        $.extend(this._defaults, this.regional['']);
        this.dpDiv = $('<div id="' + this._mainDivId + '" class="ui-entitypicker ui-picker-content' +
            ' ui-helper-clearfix ui-corner-all ui-helper-hidden-accessible"></div>');
    }

    $.extend(Entitypicker.prototype, {
        /* Class name added to elements to indicate already configured with a entity picker. */
        markerClassName: 'hasEntitypicker',

        /* Override the default settings for all instances of the entity picker.
         @param  settings  object - the new settings to use as defaults (anonymous object)
         @return the manager object */
        setDefaults: function(settings) {
            extendRemove(this._defaults, settings || {});
            return this;
        },

        /* Attach the entity picker to a jQuery selection.
         @param  target    element - the target input field or division or span
         @param  settings  object - the new settings to use for this entity picker instance (anonymous) */
        _attachEntitypicker: function(target, settings) {
            // check for settings on the control itself - in namespace 'date:'
            var inlineSettings = null;
            for (var attrName in this._defaults) {
                var attrValue = target.getAttribute('date:' + attrName);
                if (attrValue) {
                    inlineSettings = inlineSettings || {};
                    try {
                        inlineSettings[attrName] = eval(attrValue);
                    } catch (err) {
                        inlineSettings[attrName] = attrValue;
                    }
                }
            }
            var nodeName = target.nodeName.toLowerCase();
            var inline = (nodeName == 'div' || nodeName == 'span');
            if (!target.id)
                target.id = 'dp' + (++this.uuid);
            var inst = this._newInst($(target), inline);
            inst.settings = $.extend({}, settings || {}, inlineSettings || {});
            if (nodeName == 'input') {
                this._connectEntitypicker(target, inst);
            } else if (inline) {
                this._inlineEntitypicker(target, inst);
            }
        },

        /* Create a new instance object. */
        _newInst: function(target, inline) {
            var id = target[0].id.replace(/([:\[\]\.\$])/g, '\\\\$1'); // escape jQuery meta chars
            return {id: id, input: target, // associated target
                selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
                drawMonth: 0, drawYear: 0, // month being drawn
                inline: inline, // is entitypicker inline or not
                dpDiv: (!inline ? this.dpDiv : // presentation div
                    $('<div class="' + this._inlineClass + ' ui-entitypicker ui-picker-content ui-helper-clearfix ui-corner-all"></div>'))};
        },

        /* Attach the entity picker to an input field. */
        _connectEntitypicker: function(target, inst) {
            var input = $(target);
            inst.append = $([]);
            inst.trigger = $([]);
            if (input.hasClass(this.markerClassName))
                return;
            var appendText = this._get(inst, 'appendText');
            if (appendText) {
                inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
                input['after'](inst.append);
            }
            var showOn = this._get(inst, 'showOn');
            if (showOn == 'focus' || showOn == 'both') // pop-up entity picker when in the marked field
                input.focus(this._showEntitypicker);
            if (showOn == 'button' || showOn == 'both') { // pop-up entity picker when button clicked
                var buttonText = this._get(inst, 'buttonText');
                var buttonImage = this._get(inst, 'buttonImage');
                inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
                    $('<img/>').addClass(this._triggerClass).
                        attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
                    $('<button type="button"></button>').addClass(this._triggerClass).
                        html(buttonImage == '' ? buttonText : $('<img/>').attr(
                        { src:buttonImage, alt:buttonText, title:buttonText })));
                input['after'](inst.trigger);
                inst.trigger.click(function() {
                    if ($.entitypicker._entitypickerShowing && $.entitypicker._lastInput == target)
                        $.entitypicker._hideEntitypicker();
                    else
                        $.entitypicker._showEntitypicker(target);
                    return false;
                });
            }
            input.addClass(this.markerClassName).
                bind("setData.entitypicker", function(event, key, value) {
                    inst.settings[key] = value;
                }).bind("getData.entitypicker", function(event, key) {
                    return this._get(inst, key);
                });
            $.data(target, PROP_NAME, inst);
        },

        /* Attach an inline entity picker to a div. */
        _inlineEntitypicker: function(target, inst) {
            var divSpan = $(target);
            if (divSpan.hasClass(this.markerClassName))
                return;
            divSpan.addClass(this.markerClassName).append(inst.dpDiv).
                bind("setData.entitypicker", function(event, key, value) {
                    inst.settings[key] = value;
                }).bind("getData.entitypicker", function(event, key) {
                    return this._get(inst, key);
                });
            $.data(target, PROP_NAME, inst);
            this._updateEntitypicker(inst);
        },

        /* Detach a entitypicker from its control.
         @param  target    element - the target input field or division or span */
        _destroyEntitypicker: function(target) {
            var $target = $(target);
            var inst = $.data(target, PROP_NAME);
            if (!$target.hasClass(this.markerClassName)) {
                return;
            }
            var nodeName = target.nodeName.toLowerCase();
            $.removeData(target, PROP_NAME);
            if (nodeName == 'input') {
                inst.append.remove();
                inst.trigger.remove();
                $target.removeClass(this.markerClassName).
                    unbind('focus', this._showEntitypicker);
            } else if (nodeName == 'div' || nodeName == 'span')
                $target.removeClass(this.markerClassName).empty();
        },

        /* Enable the entity picker to a jQuery selection.
         @param  target    element - the target input field or division or span */
        _enableEntitypicker: function(target) {
            var $target = $(target);
            var inst = $.data(target, PROP_NAME);
            if (!$target.hasClass(this.markerClassName)) {
                return;
            }
            var nodeName = target.nodeName.toLowerCase();
            if (nodeName == 'input') {
                target.disabled = false;
                inst.trigger.filter('button').
                    each(function() {
                        this.disabled = false;
                    }).end().
                    filter('img').css({opacity: '1.0', cursor: ''});
            }
            else if (nodeName == 'div' || nodeName == 'span') {
                var inline = $target.children('.' + this._inlineClass);
                inline.children().removeClass('ui-state-disabled');
            }
            this._disabledInputs = $.map(this._disabledInputs,
                function(value) {
                    return (value == target ? null : value);
                }); // delete entry
        },

        /* Disable the entity picker to a jQuery selection.
         @param  target    element - the target input field or division or span */
        _disableEntitypicker: function(target) {
            var $target = $(target);
            var inst = $.data(target, PROP_NAME);
            if (!$target.hasClass(this.markerClassName)) {
                return;
            }
            var nodeName = target.nodeName.toLowerCase();
            if (nodeName == 'input') {
                target.disabled = true;
                inst.trigger.filter('button').
                    each(function() {
                        this.disabled = true;
                    }).end().
                    filter('img').css({opacity: '0.5', cursor: 'default'});
            }
            else if (nodeName == 'div' || nodeName == 'span') {
                var inline = $target.children('.' + this._inlineClass);
                inline.children().addClass('ui-state-disabled');
            }
            this._disabledInputs = $.map(this._disabledInputs,
                function(value) {
                    return (value == target ? null : value);
                }); // delete entry
            this._disabledInputs[this._disabledInputs.length] = target;
        },

        /* Is the first field in a jQuery collection disabled as a entitypicker?
         @param  target    element - the target input field or division or span
         @return boolean - true if disabled, false if enabled */
        _isDisabledEntitypicker: function(target) {
            if (!target) {
                return false;
            }
            for (var i = 0; i < this._disabledInputs.length; i++) {
                if (this._disabledInputs[i] == target)
                    return true;
            }
            return false;
        },

        /* Retrieve the instance data for the target control.
         @param  target  element - the target input field or division or span
         @return  object - the associated instance data
         @throws  error if a jQuery problem getting data */
        _getInst: function(target) {
            try {
                return $.data(target, PROP_NAME);
            }
            catch (err) {
                throw 'Missing instance data for this entitypicker';
            }
        },

        /* Update or retrieve the settings for a entity picker attached to an input field or division.
         @param  target  element - the target input field or division or span
         @param  name    object - the new settings to update or
         string - the name of the setting to change or retrieve,
         when retrieving also 'all' for all instance settings or
         'defaults' for all global defaults
         @param  value   any - the new value for the setting
         (omit if above is an object or to retrieve a value) */
        _optionEntitypicker: function(target, name, value) {
            var inst = this._getInst(target);
            if (arguments.length == 2 && typeof name == 'string') {
                return (name == 'defaults' ? $.extend({}, $.entitypicker._defaults) :
                    (inst ? (name == 'all' ? $.extend({}, inst.settings) :
                        this._get(inst, name)) : null));
            }
            var settings = name || {};
            if (typeof name == 'string') {
                settings = {};
                settings[name] = value;
            }
            if (inst) {
                if (this._curInst == inst) {
                    this._hideEntitypicker(null);
                }
                extendRemove(inst.settings, settings);
                this._updateEntitypicker(inst);
            }
        },

        // change method deprecated
        _changeEntitypicker: function(target, name, value) {
            this._optionEntitypicker(target, name, value);
        },

        /* Redraw the entity picker attached to an input field or division.
         @param  target  element - the target input field or division or span */
        _refreshEntitypicker: function(target) {
            var inst = this._getInst(target);
            if (inst) {
                this._updateEntitypicker(inst);
            }
        },

        /* Pop-up the entity picker for a given input field.
         @param  input  element - the input field attached to the entity picker or
         event - if triggered by focus */
        _showEntitypicker: function(input) {
            input = input.target || input;
            if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
                input = $('input', input.parentNode)[0];
            if ($.entitypicker._isDisabledEntitypicker(input) || $.entitypicker._lastInput == input) // already here
                return;
            var inst = $.entitypicker._getInst(input);
            var beforeShow = $.entitypicker._get(inst, 'beforeShow');
            extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
            $.entitypicker._hideEntitypicker(null, '');
            $.entitypicker._lastInput = input;
            if ($.entitypicker._inDialog) // hide cursor
                input.value = '';
            if (!$.entitypicker._pos) { // position below input
                $.entitypicker._pos = $.entitypicker._findPos(input);
                $.entitypicker._pos[1] += input.offsetHeight; // add the height
            }
            var isFixed = false;
            $(input).parents().each(function() {
                isFixed |= $(this).css('position') == 'fixed';
                return !isFixed;
            });
            if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
                $.entitypicker._pos[0] -= document.documentElement.scrollLeft;
                $.entitypicker._pos[1] -= document.documentElement.scrollTop;
            }
            var offset = {left: $.entitypicker._pos[0], top: $.entitypicker._pos[1]};
            $.entitypicker._pos = null;
            // determine sizing offscreen
            inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
            $.entitypicker._updateEntitypicker(inst);
            // fix width for dynamic number of entity pickers
            // and adjust position before showing
            offset = $.entitypicker._checkOffset(inst, offset, isFixed);
            inst.dpDiv.css({position: ($.entitypicker._inDialog && $.blockUI ?
                'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
                left: offset.left + 'px', top: offset.top + 'px'});
            if (!inst.inline) {
                var postProcess = function() {
                    $.entitypicker._entitypickerShowing = true;
                    var borders = $.entitypicker._getBorders(inst.dpDiv);
                    inst.dpDiv.find('iframe.ui-picker-cover').// IE6- only
                        css({left: -borders[0], top: -borders[1],
                            width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
                };
                inst.dpDiv['show'](false, postProcess);
                postProcess();
                if (inst.input.type != 'hidden')
                    inst.input.focus();
                $.entitypicker._curInst = inst;
            }
        },

        /* Generate the entity picker content. */
        _updateEntitypicker: function(inst) {
            var self = this;
            var borders = $.entitypicker._getBorders(inst.dpDiv);
            inst.dpDiv.empty().append(this._generateHTML(inst))
                .find('iframe.ui-picker-cover')// IE6- only
                .css({left: -borders[0], top: -borders[1],
                    width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
                .end()
                .find('button, .ui-entitypicker-prev, .ui-entitypicker-next, td a')
                .bind('mouseout', function() {
                    $(this).removeClass('ui-state-hover-header');
                })
                .bind('mouseover', function() {
                    if (!self._isDisabledEntitypicker(inst.inline ? inst.dpDiv.parent()[0] : inst.input)) {
                        $(this).parents('.ui-entitypicker-calendar').find('a').removeClass('ui-state-hover-header');
                        $(this).addClass('ui-state-hover-header');
                    }
                })
                .end()
                .find('button, .ui-entitypicker-calendar td a')
                .bind('mouseout', function() {
                    $(this).removeClass('ui-state-hover-content');
                })
                .bind('mouseover', function() {
                    if (!self._isDisabledEntitypicker(inst.inline ? inst.dpDiv.parent()[0] : inst.input)) {
                        $(this).parents('.ui-entitypicker-calendar').find('a').removeClass('ui-state-hover-content');
                        $(this).addClass('ui-state-hover-content');
                    }
                })
                .end()
                .find('.' + this._dayOverClass + ' a')
                .trigger('mouseover')
                .end();
            var numMonths = 12;
            var cols = numMonths[1];
            var width = 17;
            if (cols > 1)
                inst.dpDiv.addClass('ui-entitypicker-multi-' + cols).css('width', (width * cols) + 'em');
            else
                inst.dpDiv.removeClass('ui-entitypicker-multi-2 ui-entitypicker-multi-3 ui-entitypicker-multi-4').width('');
            inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
                'Class']('ui-entitypicker-multi');
            if (inst.input && inst.input.type != 'hidden' && inst == $.entitypicker._curInst)
                $(inst.input).focus();
        },

        /* Retrieve the size of left and top borders for an element.
         @param  elem  (jQuery object) the element of interest
         @return  (number[2]) the left and top borders */
        _getBorders: function(elem) {
            var convert = function(value) {
                return {thin: 1, medium: 2, thick: 3}[value] || value;
            };
            return [parseFloat(convert(elem.css('border-left-width'))),
                parseFloat(convert(elem.css('border-top-width')))];
        },

        /* Check positioning to remain on screen. */
        _checkOffset: function(inst, offset, isFixed) {
            var dpWidth = inst.dpDiv.outerWidth();
            var dpHeight = inst.dpDiv.outerHeight();
            var inputWidth = inst.input ? inst.input.outerWidth() : 0;
            var inputHeight = inst.input ? inst.input.outerHeight() : 0;
            var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
            var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();

            offset.left -= 0;
            offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
            offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;

            // now check if entitypicker is showing outside window viewport - move to a better place if so.
            offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
                Math.abs(offset.left + dpWidth - viewWidth) : 0);
            offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
                Math.abs(offset.top + dpHeight + inputHeight * 2 - viewHeight) : 0);

            return offset;
        },

        /* Find an object's position on the screen. */
        _findPos: function(obj) {
            while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
                obj = obj.nextSibling;
            }
            var position = $(obj).offset();
            return [position.left, position.top];
        },

        /* Hide the entity picker from view.
         @param  input  element - the input field attached to the entity picker
         @param  duration  string - the duration over which to close the entity picker */
        _hideEntitypicker: function(input, duration) {

            var inst = this._curInst;
            if (!inst || (input && inst != $.data(input, PROP_NAME)))
                return;

            if (this._entitypickerShowing) {
                var postProcess = function() {
                    $.entitypicker._tidyDialog(inst);
                };

                inst.dpDiv['hide'](false, postProcess);
                postProcess();

                this._entitypickerShowing = false;
                this._lastInput = null;
                if (this._inDialog) {
                    this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
                    if ($.blockUI) {
                        $.unblockUI();
                        $('body').append(this.dpDiv);
                    }
                }
                this._inDialog = false;
            }
            this._curInst = null;
        },

        /* Tidy up after a dialog display. */
        _tidyDialog: function(inst) {
            inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-entitypicker-calendar');
        },

        /* Empty the inputs */
        _clearInput: function(inst) {
            if (!inst && !(inst = this._curInst)) {
                return;
            }

            var hiddenInputId = this._get(inst, 'hiddenInputId');

            document.getElementById(hiddenInputId).value = '';
            inst.input.val('');

            // Close picker
            $.entitypicker._hideEntitypicker();
        },

        /* Transfer name and id for current entity from session */
        _saveToInput: function(inst) {
            if (!inst && !(inst = this._curInst)) {
                return;
            }

            var entityName = this._get(inst, 'entityName');
            var hiddenInputId = this._get(inst, 'hiddenInputId');

            var xmlHttpA = this._openXmlHttp();
            var xmlHttpB = this._openXmlHttp();
            if (xmlHttpA == null || xmlHttpB == null) {
                alert ('Your browser does not support Ajax HTTP');
                return;
            }

            // Fill in hidden id
            xmlHttpA.onreadystatechange = function() {
                if (xmlHttpA.readyState == 4) {
                    if (xmlHttpA.responseText.indexOf("-1") == -1) {
                        document.getElementById(hiddenInputId).value = xmlHttpA.responseText;
                        xmlHttpB.open("GET", "GetPickerDisplayVariable.jsp?e=" + entityName + "&i=" + xmlHttpA.responseText + "&guid=" + generateGUID(), true);
                        xmlHttpB.send(null);
                    }
                }
            };

            // Fill in display name
            xmlHttpB.onreadystatechange = function() {
                if (xmlHttpB.readyState == 4 && xmlHttpB.responseText.indexOf('-1') == -1) {
                    inst.input.val(xmlHttpB.responseText);
                }
            };

            // Execute ajax
            xmlHttpA.open("GET", "GetPickerIdVariable.jsp?e=" + entityName + "&guid=" + generateGUID(), true);
            xmlHttpA.send(null);

            // Close picker
            $.entitypicker._hideEntitypicker();
        },

        /* Get a setting value, defaulting if necessary. */
        _get: function(inst, name) {
            return inst.settings[name] !== undefined ?
                inst.settings[name] : this._defaults[name];
        },

        /* Generate the HTML for the current state of the entity picker. */
        _generateHTML: function(inst) {

            // Upper case leading letter in entity name
            var tmpEntityName = this._get(inst, 'entityName').charAt(0).toUpperCase() + this._get(inst, 'entityName').substring(1);

            // Generate content
            var html = '<div class="ui-picker-header ui-helper-clearfix ui-corner-all">' + this._get(inst, 'labelText') + '</div>';
            html += '<object data="' + tmpEntityName + 'PickerList.jsp" type="text/html" width="480" height="300"></object>';
            var buttonPanel = '<div class="ui-picker-buttonpane ui-picker-content">' +
                '<button type="button" class="ui-entitypicker-close ui-state-default ui-priority-primary ui-corner-all"' +
                ' onclick="javascript:DP_jQuery.entitypicker._saveToInput();">' + this._get(inst, 'submitText') + '</button>' +
                '<button type="button" class="ui-entitypicker-close ui-state-default ui-priority-primary ui-corner-all"' +
                ' onclick="javascript:DP_jQuery.entitypicker._clearInput();">' + this._get(inst, 'nullText') + '</button>' +
                '<button type="button" class="ui-entitypicker-close ui-state-default ui-priority-primary ui-corner-all"' +
                ' onclick="javascript:DP_jQuery.entitypicker._hideEntitypicker();">' + this._get(inst, 'cancelText') + '</button></div>';
            html += buttonPanel + ($.browser.msie && parseInt($.browser.version, 10) < 7 && !inst.inline ?
                '<iframe src="javascript:false;" class="ui-picker-cover" frameborder="0"></iframe>' : '');
            inst._keyEvent = false;
            return html;
        },

        _openXmlHttp: function() {
            if (typeof(XMLHttpRequest) === undefined) {
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP.6.0");
                } catch(e) {}
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP.3.0");
                } catch(e) {}
                try {
                    return new ActiveXObject("Msxml2.XMLHTTP");
                } catch(e) {}
                try {
                    return new ActiveXObject("Microsoft.XMLHTTP");
                } catch(e) {
                    return null;
                }
            }
            else {
                return new XMLHttpRequest();
            }
        }
    });

    /* jQuery extend now ignores nulls! */
    function extendRemove(target, props) {
        $.extend(target, props);
        for (var name in props)
            if (props[name] == null || props[name] == undefined)
                target[name] = props[name];
        return target;
    };

    /* Determine whether an object is an array. */
    function isArray(a) {
        return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
            (a.constructor && a.constructor.toString().match(/\Array\(\)/))));
    };

    /* Generate GUID compilant to rfc4122 v4 */
    function generateGUID() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
            return v.toString(16);
        });
    };

    /* Invoke the entity picker functionality.
     @param  options  string - a command, optionally followed by additional parameters or
     Object - settings for attaching new entitypicker functionality
     @return  jQuery object */
    $.fn.entitypicker = function(options) {

        /* Initialise the entity picker. */
        if (!$.entitypicker.initialized) {
            $(document).find('body').append($.entitypicker.dpDiv);
            $.entitypicker.initialized = true;
        }

        var otherArgs = Array.prototype.slice.call(arguments, 1);
        if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate'))
            return $.entitypicker['_' + options + 'Entitypicker'].
                apply($.entitypicker, [this[0]].concat(otherArgs));
        if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
            return $.entitypicker['_' + options + 'Entitypicker'].
                apply($.entitypicker, [this[0]].concat(otherArgs));
        return this.each(function() {
            typeof options == 'string' ?
                $.entitypicker['_' + options + 'Entitypicker'].
                    apply($.entitypicker, [this].concat(otherArgs)) :
                $.entitypicker._attachEntitypicker(this, options);
        });
    };

    $.entitypicker = new Entitypicker(); // singleton instance
    $.entitypicker.initialized = false;
    $.entitypicker.version = "@VERSION";

    // Workaround for #4055
    // Add another global to avoid noConflict issues with inline event handlers
    window.DP_jQuery = $;

})(jQuery);
